import numpy as np
from random import *
from mySort import *


def Sus(FitnV, NSel):
    """
    选择个体的序引号,锦标赛选择策略
    选择压力可以通过改变锦标赛的大小s来改变，对于较大的s值，弱者被选中的机会较小，
    常见的有二元锦标赛和三元锦标赛等。与适应度值比例选择相比，
    锦标赛选择由于缺乏随机噪声，在实际应用中经常被使用，同时锦标赛选择也和遗传算法适应度函数的尺度无关，
    因为只需要比较绝对值大小，不用考虑正负的问题。
    :param FitnV: 种群中个体的适应度值
    :param NSel: 被选择个体的数目
    :return:NewChrIx: 选择个体的序引号
    """
    NSel = int(NSel)
    (Nind, ans) = FitnV.shape  # Nind为FitnV的行数也就是个体数 ans为列数1

    OldChrIx = [i for i in range(Nind)]
    NewChrIx = list()

    while len(NewChrIx) < NSel:
        f1 = randint(0, len(OldChrIx)-1)
        f2 = randint(0, len(OldChrIx)-1)
        f3 = randint(0, len(OldChrIx)-1)
        f4 = randint(0, len(OldChrIx) - 1)
        while f2 == f1:
            f2 = randint(0, len(OldChrIx)-1)
        while f3 == f2 or f3 == f1:
            f3 = randint(0, len(OldChrIx) - 1)
        while f4 == f1 or f4 == f2 or f4 == f3:
            f4 = randint(0, len(OldChrIx) - 1)

        index1 = OldChrIx[f1]
        v1 = FitnV[index1]

        index2 = OldChrIx[f2]
        v2 = FitnV[index2]

        index3 = OldChrIx[f3]
        v3 = FitnV[index3]

        index4 = OldChrIx[f4]
        v4 = FitnV[index4]

        maxV = np.max([v1, v2, v3, v4])
        if maxV == v1:
            NewChrIx.append(OldChrIx[f1])
            del OldChrIx[f1]
        elif maxV == v2:
            NewChrIx.append(OldChrIx[f2])
            del OldChrIx[f2]
        elif maxV == v3:
            NewChrIx.append(OldChrIx[f3])
            del OldChrIx[f3]
        else:
            NewChrIx.append(OldChrIx[f4])
            del OldChrIx[f4]

    [_, sbuf] = mySort(np.array([random() for _ in range(NSel)]))
    NewChrIx = np.array(NewChrIx)
    return NewChrIx[sbuf]